﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.LiveFX.Client;
using System.Net;
using Microsoft.LiveFX.ResourceModel;
using System.IO;

namespace a_fung
{
	public partial class Prototype : Form
	{
		const string PROTOTYPE_TYPE = "LiveMeshFolder";
		const string PROTOTYPE_TYPE_FILES = "LiveMeshFiles";
		const string FILE_HANDLER_TYPE = "FileSystem";

		LiveOperatingEnvironment env = new LiveOperatingEnvironment();
		Mesh mesh = null;
		MeshObject theMeshObject = null;
		DataFeed theDataFeed = null;

		string userName = "TestUser";

		delegate void safeCallback();

		public Prototype(Connecting connecting)
		{
			InitializeComponent();
			this.FormClosing += new FormClosingEventHandler(Cleanup);

			LiveItemAccessOptions accessOptions = new LiveItemAccessOptions(true);

			// connect
			//
			try
			{
				string address = "test@a-fung.net";

				string password = "whAtIsApAsswOrd!";

				string uri = Properties.Resources.Uri;

				if (string.IsNullOrEmpty(uri))
				{
					MessageBox.Show("No URI in the resources file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}

				// Create user token
				String token = new NetworkCredential(address, password, uri).GetWindowsLiveAuthenticationToken();

				// Create URI for cloud Mesh
				Uri theUri = new Uri(uri);

				env.Connect(token, AuthenticationTokenType.UserToken, theUri, accessOptions);

				mesh = env.Mesh;
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught exception trying to connect: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				Application.Exit();
			}

			// get user meshObject
			//
			MeshObject meshObject = (from mo in mesh.CreateQuery<MeshObject>()
									 where mo.Resource.Title == userName
									 select mo).FirstOrDefault<MeshObject>();

			if (meshObject == null)
			{
				try
				{
					string meshObjectName = userName;

					// Create Mesh object
					theMeshObject = new MeshObject(meshObjectName);

					// Set its type to Mesh folder
					theMeshObject.Resource.Type = PROTOTYPE_TYPE;

					// Add new Mesh object to collection
					mesh.MeshObjects.Add(ref theMeshObject);

					// Create DataFeed for files
					theDataFeed = new DataFeed(PROTOTYPE_TYPE_FILES);

					// Set type and handler type
					theDataFeed.Resource.Type = PROTOTYPE_TYPE_FILES;
					theDataFeed.Resource.HandlerType = FILE_HANDLER_TYPE;

					// Add new data feed to collection
					theMeshObject.DataFeeds.Add(ref theDataFeed);
				}
				catch (Exception ex)
				{
					MessageBox.Show("Caught exception trying to connect: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					Application.Exit();
				}
			}
			else
			{
				theDataFeed = (from dataFeed in meshObject.CreateQuery<DataFeed>()
							   where dataFeed.Resource.Title == PROTOTYPE_TYPE_FILES
							   select dataFeed).FirstOrDefault<DataFeed>();
			}

			// get all items
			//
			GetAndUpdateItems();

			theDataFeed.DataEntries.ChangeNotificationReceived += new EventHandler(meshObject_ChangeNotificationReceived);

			connecting.Invoke(new safeCallback(connecting.Hide));
		}

		void meshObject_ChangeNotificationReceived(object sender, EventArgs e)
		{
			DataEntryCollection dec = (DataEntryCollection)sender;
            
			string notification = "Notification received:" + Environment.NewLine;

			foreach (DataEntry de in dec.Entries)
			{
				notification += String.Format(
					"id: {0}, title: {1}{3}{2}{3}{3}",
					de.Resource.Title,
					de.Resource.GetUserData<PrototypeItem>().title,
					de.Resource.LastUpdatedTime.ToString(),
					Environment.NewLine);
			}

			notificationBox.Text += notification + Environment.NewLine + Environment.NewLine;
			notificationBox.SelectionStart = notificationBox.Text.Length;
			notificationBox.ScrollToCaret();

//			if (HasConflicts(theDataFeed)) ResolveConflicts(theDataFeed);

			GetAndUpdateItems();
		}

        DataEntry[] testde;
		void GetAndUpdateItems()
		{
			itemList.Items.Clear();

			var dataEntries = (from dataEntry in theDataFeed.CreateQuery<DataEntry>().Execute()
							   select dataEntry);

			if (dataEntries.Count() > 0)
			{
				foreach (DataEntry dataEntry in dataEntries)
				{
					// Show title of prototype item
					//
					PrototypeItem theItem = dataEntry.Resource.GetUserData<PrototypeItem>();
					if (theItem == null) continue;

					itemList.Items.Add(theItem);
				}
			}
            testde = dataEntries.ToArray();
		}

		void Cleanup(object sender, FormClosingEventArgs e)
		{
		}

		private void addButton_Click(object sender, EventArgs e)
		{
			new PrototypeItemWindow(this).Show();
		}

		public void AddItem(PrototypeItem item)
		{
			try
			{
				Random r = new Random();
				string filename = "";

				do
				{
					filename = filename + r.Next().ToString();
				}
				while (ItemExist(filename));

				item.id = filename;

				MemoryStream mStream = new MemoryStream();
				StreamWriter sWriter = new StreamWriter(mStream);
				sWriter.Write(filename);
				mStream.Seek(0, SeekOrigin.Begin);

				DataEntry dataEntry = theDataFeed.DataEntries.Add(mStream, filename, null);

				// Add prototype item
				//
				dataEntry.Resource.SetUserData<PrototypeItem>(item);

				// Required to see user data on all devices/Live Desktop/Data Model Browser
				dataEntry.UpdateAsync(null);

				// Make sure everyone is synchronized
				theDataFeed.SyncEntries.SynchronizeAsync(null);
				theDataFeed.UpdateAsync(null);

				sWriter.Close();
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught Exception adding an item: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private bool ItemExist(string id)
		{
			var dataEntries = (from dataEntry in theDataFeed.CreateQuery<DataEntry>()
							   where dataEntry.Resource.Title == id
							   select dataEntry);

			foreach (DataEntry de in dataEntries) return true;

			return false;
		}

		private void itemList_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			if (itemList.SelectedItem == null) return;
			if (!(itemList.SelectedItem is PrototypeItem)) return;
			PrototypeItem item = (PrototypeItem)itemList.SelectedItem;
			if (item == null) return;
			new PrototypeItemWindow(this, item.id, item).MyShow();
		}

		PrototypeItem GetItemByTitle(string title)
		{
			var dataEntries = (from dataEntry in theDataFeed.CreateQuery<DataEntry>().Execute()
							   select dataEntry);

			if (dataEntries.Count() > 0)
			{
				foreach (DataEntry dataEntry in dataEntries)
				{
					// Show title of prototype item
					//
					PrototypeItem theItem = dataEntry.Resource.GetUserData<PrototypeItem>();
					if (theItem == null) continue;

					if (theItem.title == title) return theItem;
				}
			}

			return null;
		}

		DataEntry GetDataEntryById(string id)
		{
			var dataEntries = (from dataEntry in theDataFeed.CreateQuery<DataEntry>().Execute()
							   where dataEntry.Resource.Title == id
							   select dataEntry);

			if (dataEntries.Count() > 0)
			{
				foreach (DataEntry dataEntry in dataEntries)
				{
					return dataEntry;
				}
			}

			return null;
		}

		public void UpdateItem(PrototypeItem item)
		{
			try
			{
				DataEntry dataEntry = GetDataEntryById(item.id);

				// Update prototype item
				//
				dataEntry.Resource.SetUserData<PrototypeItem>(item);

				// Required to see user data on all devices/Live Desktop/Data Model Browser
				dataEntry.UpdateAsync(null);

				// Make sure everyone is synchronized
				theDataFeed.SyncEntries.SynchronizeAsync(null);
				theDataFeed.UpdateAsync(null);
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught Exception updating an item: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		PrototypeItem deleteItem = null;

		private void DeleteButton_Click(object sender, EventArgs e)
		{
			if (itemList.SelectedItem == null) return;
			if (!(itemList.SelectedItem is PrototypeItem)) return;
			deleteItem = (PrototypeItem)itemList.SelectedItem;

			new System.Threading.Thread(DeleteButton_Click).Start();
		}

		private void DeleteButton_Click()
		{
			PrototypeItem item = deleteItem;

			if (item == null) return;

			try
			{
				DataEntry dataEntry = GetDataEntryById(item.id);

				// Required to see user data on all devices/Live Desktop/Data Model Browser
				theDataFeed.DataEntries.Remove(dataEntry);

				// Make sure everyone is synchronized
				theDataFeed.SyncEntries.SynchronizeAsync(null);
				theDataFeed.UpdateAsync(null);
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught Exception updating an item: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		bool HasConflicts(DataFeed dataFeed)
		{
			var syncEntries = (from dataEntry in dataFeed.SyncEntries.Entries
							   select dataEntry);

			foreach (DataEntry dataEntry in syncEntries)
			{
				if (dataEntry.Resource.Sync.Conflicts.Count > 0)
				{
					return true;
				}
			}

			return false;
		}

		void ResolveConflicts(DataFeed dataFeed)
		{
			var dataEntries = (from de in dataFeed.SyncEntries.Entries
							   where de.Resource.Sync.Conflicts.Count > 0
							   select de);

			foreach (DataEntry dataEntry in dataEntries)
			{
				dataEntry.ResolveAllConflictsAsync(null);
			}

			dataFeed.SyncEntries.SynchronizeAsync(null);
		}

	}
}
